#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

#define MAX 512

main(int argc, char *argv[])
{	
	DIR *dp;
	struct dirent *dr;
	char *dir = NULL;
	
	char fn[MAX];   //save the filename
	char list[MAX];
	char buf[MAX];
	struct stat st;
	int index;
	
	int i;
	int opt_l;
	int opt_a;
	int opt_al;

	if( 1 == argc )
	{
		dir = ".";
	}
	else
	{
		for(i=1; i<argc; i++)
		{
			if( '-' != argv[i][0] )
			{
				dir = argv[i];
				break;
			}
		}

		if( NULL == dir )
			dir = ".";
	}
	
	if((dp=opendir(dir))==NULL){
		perror("opendir failed");
		exit(1);
	}
		
	opt_l = check_argv(argv, "-l");
	opt_a = check_argv(argv, "-a");
	opt_al = check_argv(argv, "-al");

	while(dr=readdir(dp)){
		if(!opt_a){
			if(strncmp(dr->d_name, ".", 1))
			printf("%s ", dr->d_name);
			}
	
		if(opt_a){
			printf("%s ", dr->d_name);
			}
	
		if(opt_l){
		
			index=0;
		
			if(!strncmp(dr->d_name, ".", 1))
				continue;
		
			sprintf(fn, "%s/%s", dir, dr->d_name);
	
			if(lstat(fn, &st)==-1){
				perror("stat failed");
				exit(1);
			}
	
			switch(st.st_mode & S_IFMT){
		
				case S_IFMT :
					list[index++] = '-';
					break;

				case S_IFDIR :
					list[index++] = 'd';
					break;

				case S_IFIFO :
					list[index++] = 'p';
					break;

				case S_IFLNK :
					list[index++] = '1';
					}
	
			for(i=0; i<3; i++){
				if(st.st_mode & (S_IREAD >> i*3))
					list[index++] = 'r';
		
				else
					list[index++] = '-';
		
				if(st.st_mode & (S_IWRITE >> i*3))
					list[index++] = 'w';
		
				else
					list[index++] = '-';
		
				if(st.st_mode & (S_IEXEC >> i*3))
					list[index++] = 'x';
		
				else
					list[index++] = '-';
				}
	
			list[index] = '\0';

			printf("%s%5d %s ", list, st.st_nlink, (getpwuid(st.st_uid))->pw_name);
			printf("%s%9d ", (getgrgid(st.st_gid))->gr_name, st.st_size);
			sprintf(buf, "%s", ctime(&st.st_mtime));
			buf[strlen(buf)-1] = '\0';
			printf("%s %s\n", buf, dr->d_name);	
		}
	
		if(opt_al){
	
			index=0;
	
			sprintf(fn, "%s/%s", dir, dr->d_name);
	
			if(lstat(fn, &st)==-1){
				perror("stat failed");
				exit(1);
			}
	
			switch(st.st_mode & S_IFMT){

				case S_IFMT :
					list[index++] = '-';
					break;
			
				case S_IFDIR :
					list[index++] = 'd';
					break;

				case S_IFIFO :
					list[index++] = 'p';
					break;
			
				case S_IFLNK :
					list[index++] = '1';
			}
	
			for(i=0; i<3; i++){
		
				if(st.st_mode & (S_IREAD >> i*3))
					list[index++] = 'r';
		
				else
					list[index++] = '-';
		
				if(st.st_mode & (S_IWRITE >> i*3))
					list[index++] = 'w';
		
				else
					list[index++] = '-';
		
				if(st.st_mode & (S_IEXEC >> i*3))
					list[index++] = 'x';
		
				else
					list[index++] = '-';
			}
	
			list[index] = '\0';

			printf("%s%5d %s ", list, st.st_nlink, (getpwuid(st.st_uid))->pw_name);
			printf("%s%9d ", (getgrgid(st.st_gid))->gr_name, st.st_size);
			sprintf(buf, "%s", ctime(&st.st_mtime));
			buf[strlen(buf)-1] = '\0';
			printf("%s %s\n", buf, dr->d_name);	
		}
	}
		
	printf("\n");
	closedir(dp);
	exit(0);	
}

//option check function
int check_argv(char *argv[], const char *opt)
{
	int count = 0;

	while(*argv != '\0')
	{
		if(!strcmp(argv[count], opt))
		{
			return 1;
		}

		argv++;
	}

	return 0;
}
